package entity;

import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;


@SuppressWarnings("serial")
@PersistenceCapable
public class ImageItem implements Serializable {

	@PrimaryKey
    @Persistent
    private String url;
	@Persistent
    private String title;
	@Persistent
    private String comment;
	@Persistent
    private boolean catTag;
	@Persistent
    private boolean dogTag;
	@Persistent
    private boolean birdTag;
	@Persistent
    private boolean petsTag;
	@Persistent
    private boolean wildlifeTag;
	@Persistent
    private boolean humanTag;	
	@Persistent
    private int rating;
	@Persistent
    private int num_duels; 
	@Persistent
    private String user; 
	
    private static final int DEFAULT_RATING = 1500;

    public ImageItem(Entity entity) {
    	//System.out.println(entity);
    	
        this.url = entity.getKey().getName();
        this.setTitle((String) entity.getProperty("title"));
        this.setComment((String) entity.getProperty("comment"));
        this.setCatTag((Boolean) entity.getProperty("catTag"));
        this.setDogTag((Boolean) entity.getProperty("dogTag"));
        this.setBirdTag((Boolean) entity.getProperty("birdTag"));
        this.setPetsTag((Boolean) entity.getProperty("petsTag"));
        this.setWildlifeTag((Boolean) entity.getProperty("wildlifeTag"));
        this.setHumanTag((Boolean) entity.getProperty("humanTag"));
        
        int rating = DEFAULT_RATING;
        Object objectRating = entity.getProperty("rating");
        if (objectRating instanceof Long) {
        	rating = (int)(long)(Long)objectRating;
        }
        else if (objectRating instanceof Integer){
        	rating = (Integer)objectRating;
        }
        this.setRating(rating);
        
        int numDuels = 0;
        Object objectDuels= entity.getProperty("rating");
        if (objectDuels instanceof Long) {
        	numDuels = (int)(long)(Long)objectRating;
        }
        else if (objectRating instanceof Integer){
        	numDuels = (Integer)objectRating;
        }
        this.setNum_duels(numDuels);
        this.setUser((String) entity.getProperty("user"));
	}
    
    public ImageItem(String _url, String _title) {
        this.setUrl(_url);
        this.setTitle(_title);
        this.setCatTag(false);
        this.setDogTag(false);
        this.setBirdTag(false);
        this.setPetsTag(false);
        this.setWildlifeTag(false);
        this.setHumanTag(false);
        //make tags an empty list
        this.setRating(DEFAULT_RATING);
        this.setNum_duels(0);
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();
        if (user == null) {
        	this.setUser("anonymous");
        } else  {
        	this.setUser(user.getNickname());
        }
        
        System.out.println("New Image: " + this);
        //save();
    }
    
    public ImageItem(String _url, String _title, String _comment, boolean _catTag, boolean _dogTag, boolean _birdTag, boolean _petsTag, boolean _wildlifeTag, boolean _humanTag,int _rating, int _num_duels, String _user) {
        this.setUrl(_url);
        this.setTitle(_title);
        this.setComment(_comment);
        this.setCatTag(_catTag);
        this.setDogTag(_dogTag);
        this.setBirdTag(_birdTag);
        this.setPetsTag(_petsTag);
        this.setWildlifeTag(_wildlifeTag);
        this.setHumanTag(_humanTag);
        this.setRating(_rating);
        this.setNum_duels(_num_duels);
        this.setUser(_user);
        System.out.println("New Image: " + this);
        save();
    }
    
    public ImageItem(String _url, String _title, String _comment, String tags ,int _rating, int _num_duels, String _user) {
        this.setUrl(_url);
        this.setTitle(_title);
        this.setComment(_comment);
        this.setTags(tags);
        this.setRating(_rating);
        this.setNum_duels(_num_duels);
        this.setUser(_user);
        
        System.out.println("New Image: " + this);
        save();
    }

	/**
	 * @return the url
	 */
	public String getUrl() {
		return url;
	}

	/**
	 * @param url the url to set
	 */
	public void setUrl(String url) {
		URLFetchService fetchService = URLFetchServiceFactory.getURLFetchService();
		FileService fileService = FileServiceFactory.getFileService();
		ImagesService imagesService = ImagesServiceFactory.getImagesService();

		HTTPResponse fetchResponse;
		try {
			fetchResponse = fetchService.fetch(new URL(url));
			Image originalImage = ImagesServiceFactory.makeImage(fetchResponse.getContent());

			AppEngineFile file = fileService.createNewBlobFile("image/" + originalImage.getFormat());
			FileWriteChannel writeChannel = fileService.openWriteChannel(file, true);
			ByteBuffer buffer = ByteBuffer.wrap(originalImage.getImageData());
			writeChannel.write(buffer);
			writeChannel.closeFinally();
			BlobKey key = fileService.getBlobKey(file);
			String servingURL = imagesService.getServingUrl(key);
			if (servingURL != null) {
				this.url = servingURL;
			}
			else {
				System.err.println("Unable to create a URL for the image");
				this.url = url;
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * @return the title
	 */
	public String getTitle() {
		return title;
	}

	/**
	 * @param title the title to set
	 */
	public void setTitle(String title) {
		this.title = title; //escapeJSCharacters(title);		
	}

	/**
	 * @return the comment
	 */
	public String getComment() {
		return comment;
	}

	/**
	 * @param comment the comment to set, sanitizes ugly characters
	 */
	public void setComment(String comment) {
		this.comment = comment; //escapeJSCharacters(comment);
	}

	/**
	 * @return the rating
	 */
	public int getRating() {
		return rating;
	}

	/**
	 * @param rating the rating to set
	 */
	public void setRating(int rating) {
		this.rating = rating;
	}

	/**
	 * @return the num_duels
	 */
	public int getNum_duels() {
		return num_duels;
	}

	/**
	 * @param num_duels the num_duels to set
	 */
	public void setNum_duels(int num_duels) {
		this.num_duels = num_duels;
	}

    public void save() {
    	entity.User.itemSaveTrigger(this.user);
    	EntityManagerFactory emf = EMF.get();
    	if (emf == null) {
    		System.out.println("Unable to initialize the entity manager");
    		return;
    	}
        EntityManager em = emf.createEntityManager();
        try {
            em.merge(this);
        } finally {
            em.close();
        }
    }

    public static ImageItem get(String url)
    {
    	ImageItem imageItem = null;
    	EntityManager em = EMF.get().createEntityManager();
        try {
            imageItem = em.find(ImageItem.class, url);
        } finally {
            em.close();
        }
        return imageItem;
    }
    
	/**
	 * @return a constructed String of tags
	 */
	public String printTags() {
		String tags = "";
		if (catTag)
			tags = tags.concat("cat|");
		if (dogTag)
			tags = tags.concat("dog|");
		if (birdTag)
			tags = tags.concat("bird|");
		if (petsTag)
		    tags = tags.concat("pets|");
		if (wildlifeTag)
		    tags = tags.concat("wildlife|");
		if (humanTag)
		    tags = tags.concat("human|");
		//chop last char
		if(tags.length() > 0)
		    tags = tags.substring(0, tags.length() - 1);
		return tags;
	}
	
	/**
	 * @return a List<String> of tags
	 */
	public List<String> getTags() {
		List<String> tagList = new ArrayList<String>();
		if (catTag)
			tagList.add("cat");
		if (dogTag)
			tagList.add("dog");
		if (birdTag)
			tagList.add("bird");
		if (petsTag)
			tagList.add("pet");
		if (wildlifeTag)
			tagList.add("wildlife");
		if (humanTag)
			tagList.add("human");
		return tagList;
	}	

	/**
	 * @param tags to set
	 */
	public void setTags(String tags) {
        this.setCatTag((tags.indexOf("cat") >= 0) ? true : false);
        this.setDogTag((tags.indexOf("dog") >= 0) ? true : false);
        this.setBirdTag((tags.indexOf("bird") >= 0) ? true : false);
        this.setPetsTag((tags.indexOf("pets") >= 0) ? true : false);
        this.setWildlifeTag((tags.indexOf("wildlife") >= 0) ? true : false);
        this.setHumanTag((tags.indexOf("human") >= 0) ? true : false);
	}
    
	public String toString() {
		return "|url:"+url+"|title:"+title+"|comment:"+comment+"|tags:{"+printTags()+"}|rating:"+rating+"|num_duels:"+num_duels+"|user:"+user;		
	}

	/**
	 * @return the catTag
	 */
	public boolean isCatTag() {
		return catTag;
	}

	/**
	 * @param catTag the catTag to set
	 */
	public void setCatTag(boolean catTag) {
		this.catTag = catTag;
	}

	/**
	 * @return the dogTag
	 */
	public boolean isDogTag() {
		return dogTag;
	}

	/**
	 * @param dogTag the dogTag to set
	 */
	public void setDogTag(boolean dogTag) {
		this.dogTag = dogTag;
	}

	/**
	 * @return the birdTag
	 */
	public boolean isBirdTag() {
		return birdTag;
	}

	/**
	 * @param birdTag the birdTag to set
	 */
	public void setBirdTag(boolean birdTag) {
		this.birdTag = birdTag;
	}

	/**
	 * @return the petsTag
	 */
	public boolean isPetsTag() {
		return petsTag;
	}

	/**
	 * @param petsTag the petsTag to set
	 */
	public void setPetsTag(boolean petsTag) {
		this.petsTag = petsTag;
	}

	/**
	 * @return the wildlifeTag
	 */
	public boolean isWildlifeTag() {
		return wildlifeTag;
	}

	/**
	 * @param wildlifeTag the wildlifeTag to set
	 */
	public void setWildlifeTag(boolean wildlifeTag) {
		this.wildlifeTag = wildlifeTag;
	}

	/**
	 * @return the humanTag
	 */
	public boolean isHumanTag() {
		return humanTag;
	}

	/**
	 * @param humanTag the humanTag to set
	 */
	public void setHumanTag(boolean humanTag) {
		this.humanTag = humanTag;
	}

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}
	
	public static String escapeJSCharacters(String aString) {
		if (aString == null) {
			return "";
		} else {
			return aString.replace("\\", "\\\\").replace("\'", "\\\'").replace("\"", "\\\"");
		}
	}

}
